import cv2
import numpy as np
import os
import shutil
import tkinter as tk
from tkinter import Tk, Frame, Entry, Label, Button, Text, END, messagebox
import webbrowser

# ----- Start of slice Code -----

def slice_characters_from_image(img, min_width=20, min_height=20):
    alpha_channel = img[:, :, 3]
    _, binary = cv2.threshold(alpha_channel, 0, 255, cv2.THRESH_BINARY)
    
    # 针对复杂汉字的多步形态学处理
    # 第一步：使用大核进行强力闭运算，连接字符的所有笔画
    kernel_large = np.ones((7, 7), np.uint8)
    binary = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel_large, iterations=5)
    
    # 第二步：膨胀操作，进一步连接可能断开的部分
    kernel_dilate = np.ones((3, 3), np.uint8)
    binary = cv2.dilate(binary, kernel_dilate, iterations=2)
    
    # 第三步：再次闭运算，确保字符完整性
    kernel_close = np.ones((5, 5), np.uint8)
    binary = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel_close, iterations=3)
    
    # 去除小的噪声点
    kernel_small = np.ones((3, 3), np.uint8)
    binary = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel_small, iterations=1)
    
    # 使用RETR_TREE来获取所有轮廓层次，然后合并相近的轮廓
    contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    
    # 合并相近的轮廓边界框
    bboxes = []
    for contour in contours:
        x, y, w, h = cv2.boundingRect(contour)
        if w >= min_width and h >= min_height:
            bboxes.append([x, y, x+w, y+h, contour])
    
    # 合并重叠或相近的边界框
    merged_bboxes = []
    used = [False] * len(bboxes)
    
    for i in range(len(bboxes)):
        if used[i]:
            continue
            
        current_bbox = bboxes[i][:4]
        merged_contours = [bboxes[i][4]]
        used[i] = True
        
        # 检查是否有其他边界框需要合并
        for j in range(i+1, len(bboxes)):
            if used[j]:
                continue
                
            other_bbox = bboxes[j][:4]
            
            # 计算两个边界框的距离和重叠情况
            x1, y1, x2, y2 = current_bbox
            ox1, oy1, ox2, oy2 = other_bbox
            
            # 计算中心点距离
            center1_x, center1_y = (x1 + x2) // 2, (y1 + y2) // 2
            center2_x, center2_y = (ox1 + ox2) // 2, (oy1 + oy2) // 2
            distance = ((center1_x - center2_x) ** 2 + (center1_y - center2_y) ** 2) ** 0.5
            
            # 如果距离小于字符大小，认为是同一个字符的不同部分
            char_size = max(x2-x1, y2-y1, ox2-ox1, oy2-oy1)
            if distance < char_size * 0.8:  # 距离小于字符大小的80%时合并
                # 合并边界框
                current_bbox = [min(x1, ox1), min(y1, oy1), max(x2, ox2), max(y2, oy2)]
                merged_contours.append(bboxes[j][4])
                used[j] = True
        
        merged_bboxes.append((current_bbox, merged_contours))
    
    slices = []
    
    for bbox, contours_group in merged_bboxes:
        x1, y1, x2, y2 = bbox
        w, h = x2 - x1, y2 - y1
        
        # 过滤过于细长的区域（可能是线条或噪声）
        aspect_ratio = max(w, h) / min(w, h)
        if aspect_ratio > 5:  # 长宽比超过5:1的跳过
            continue
        
        # 计算所有轮廓的总面积
        total_area = sum(cv2.contourArea(contour) for contour in contours_group)
        bbox_area = w * h
        if total_area < bbox_area * 0.05:  # 轮廓总面积小于边界框面积的5%时跳过
            continue
        
        # 创建正方形画布，边长为较大的一边再加一些边距
        max_side = max(w, h) + 40  # 增加40像素边距，给复杂字符更多空间
        canvas = np.zeros((max_side, max_side, 4), dtype=np.uint8)
        
        # 计算字符在画布中的居中位置
        x_offset = (max_side - w) // 2
        y_offset = (max_side - h) // 2
        
        # 将字符复制到画布中心
        canvas[y_offset:y_offset + h, x_offset:x_offset + w] = img[y1:y2, x1:x2]
        slices.append(canvas)
    
    return slices

def main(min_width, min_height, progress_text):
    input_folder = 'pic'
    output_folder = 'output_slices'

    if os.path.exists(output_folder):
        for file_name in os.listdir(output_folder):
            file_path = os.path.join(output_folder, file_name)
            try:
                if os.path.isfile(file_path) or os.path.islink(file_path):
                    os.unlink(file_path)
                elif os.path.isdir(file_path):
                    shutil.rmtree(file_path)
            except Exception as e:
                progress_text.insert(END, f"Error deleting file : {file_path}. Reason: {e}\n")
                progress_text.see(END)

    if not os.path.exists(output_folder):
        os.makedirs(output_folder)

    for img_name in os.listdir(input_folder):
        if img_name.lower().endswith('.png'):
            img_path = os.path.join(input_folder, img_name)
            progress_text.insert(END, f"Reading image from: {img_path}\n")
            progress_text.see(END)

            if not os.path.exists(img_path):
                progress_text.insert(END, f"Cannot find image: {img_name}\n")
                continue

            img = cv2.imdecode(np.fromfile(img_path, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
            if img is None:
                progress_text.insert(END, f"Cannot read image: {img_name}\n")
                continue

            slices = slice_characters_from_image(img, min_width, min_height)
            for i, slice_img in enumerate(slices):
                output_name = os.path.join(output_folder, f'slice_{os.path.splitext(img_name)[0]}_{i}.png')
                cv2.imencode('.png', slice_img)[1].tofile(output_name)

    progress_text.insert(END, "批量处理完成！\n")
    progress_text.see(END)

def on_run_button_click(min_width_entry, min_height_entry, progress_text):
    progress_text.delete(1.0, END)
    min_width = int(min_width_entry.get())
    min_height = int(min_height_entry.get())

    try:
        main(min_width, min_height, progress_text)
    except Exception as e:
        messagebox.showerror("错误", str(e))

def center_window(window, width=600, height=480):
    """Center a tkinter window on the screen."""
    screen_width = window.winfo_screenwidth()
    screen_height = window.winfo_screenheight()
    x = (screen_width - width) // 2
    y = (screen_height - height) // 2
    window.geometry(f"{width}x{height}+{x}+{y}")

def slice_tool():
    root = tk.Tk()
    root.title("批量切图工具")
    main_frame = Frame(root)
    main_frame.pack(pady=20, padx=10)

    Label(main_frame, text="Min Width:").grid(row=0, column=0, padx=10, pady=5)
    min_width_entry = Entry(main_frame)
    min_width_entry.grid(row=0, column=1, padx=10, pady=10)
    min_width_entry.insert(0, "20")

    Label(main_frame, text="Min Height:").grid(row=1, column=0, padx=10, pady=0)
    min_height_entry = Entry(main_frame)
    min_height_entry.grid(row=1, column=1, padx=10, pady=0)
    min_height_entry.insert(0, "20")

    button_frame = tk.Frame(root)
    button_frame.pack(pady=0, padx=0)

    Button(button_frame, text="开始处理", command=lambda: on_run_button_click(min_width_entry, min_height_entry, progress_text)).grid(row=2, column=0, columnspan=2, pady=15)
    
    progress_frame = tk.Frame(root)
    progress_frame.pack(padx=20, pady=0, fill=tk.BOTH, expand=True)

    info_label_text = "图片只支持PNG背景透明，切图尺寸调整宽高阀值。"
    info_label = tk.Label(button_frame, text=info_label_text, font=('Arial', 12))
    info_label.grid(row=3, column=0, columnspan=2, pady=15)

    def open_url(event):
        webbrowser.open("https://www.douyin.com/user/MS4wLjABAAAAqiYlKxHAlPI_QzUANR22KZbclBuzbHruD0tqZH5EsoE")

    label_text = "关注速光网络抖音号：dubaishun12\n私信博主，免费获取注册码！"
    label_font = ('Arial', 12, 'bold')
    label_foreground = "blue"
    label_background = "orange"

    label = tk.Label(progress_frame, text=label_text, font=label_font, fg=label_foreground, bg=label_background, cursor="hand2")
    label.pack(pady=5)
    label.bind("<Button-1>", open_url)

    progress_text = tk.Text(progress_frame, width=55, height=15)
    progress_text.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)

    center_window(root)  # 确保窗口在屏幕中间

    root.mainloop()

slice_tool()
